<template>
  <div class="m-table-container">
    <slot name="beforeTable"></slot>
    
    <el-table
      :data="tableData"
      :max-height="tableHeight"
      @selection-change="handleSelectionChange"
      :row-key="rowKey"
      v-bind="$attrs"
      :header-cell-style="headerCellStyle"
      :row-class-name="rowClassName"
      :cell-class-name="cellClassName"
      @row-click="handleRowClick"
      @sort-change="handleSortChange"
    >
      <!-- 序号列 -->
      <el-table-column 
        v-if="showIndex" 
        type="index" 
        :label="indexLabel"
        :width="indexWidth"  
        align="center"
      />
      
      <!-- 选择列 -->
      <el-table-column 
        v-if="showSelection" 
        type="selection" 
        :width="selectionWidth" 
        align="center"
        :selectable="selectable"
      />
      
      <!-- 展开列 -->
      <el-table-column 
        v-if="expandable"
        type="expand"
        :width="expandWidth"
        align="center"
      >
        <template #default="scope">
          <slot name="expand" :row="scope.row" :index="scope.$index"></slot>
        </template>
      </el-table-column>
      
      <!-- 动态列 -->
      <template v-for="(column, index) in columns" :key="index">
        <el-table-column
          :prop="column.prop"
          :label="column.label"
          :width="column.width"
          :min-width="column.minWidth"
          :fixed="column.fixed"
          :sortable="column.sortable"
          :show-overflow-tooltip="column.showOverflowTooltip !== false"
          :align="column.align || 'center'"
          :formatter="column.formatter"
        >
          <!-- 自定义表头 -->
          <template #header v-if="column.renderHeader">
            <slot :name="`header-${column.prop}`" :column="column">
              <component
                v-if="column.headerComponent"
                :is="column.headerComponent"
                :column="column"
              />
              <span v-else>{{ column.label }}</span>
            </slot>
          </template>
          
          <!-- 自定义内容 -->
          <template #default="scope">
            <!-- 支持命名插槽方式 -->
            <slot :name="column.prop" :row="scope.row" :column="column" :index="scope.$index">
              <!-- 支持renderContent函数方式 -->
              <component
                v-if="column.renderContent && typeof column.renderContent === 'function'"
                :is="column.renderContent(scope.row, column, scope.$index)"
              />
              
              <!-- 支持指定组件方式 -->
              <component
                v-else-if="column.component"
                :is="column.component"
                v-bind="getComponentProps(column, scope.row)"
                @click="handleComponentClick(column, scope.row, scope.$index, $event)"
              />
              
              <!-- 支持按钮数组方式 -->
              <div v-else-if="column.buttons" class="button-group">
                <component
                  v-for="(button, bIndex) in resolveButtons(column.buttons, scope.row)"
                  :key="bIndex"
                  :is="button.component || 'el-button'"
                  v-bind="button.props || {}"
                  :disabled="button.disabled"
                  :style="button.style"
                  :class="button.class"
                  v-show="isButtonVisible(button, scope.row)"
                  @click.stop="handleButtonClick(button, scope.row, scope.$index, $event)"
                >
                  <template v-if="button.icon">
                    <component :is="button.icon" v-if="typeof button.icon === 'object'" />
                    <i v-else :class="button.icon"></i>
                  </template>
                  {{ button.label }}
                </component>
              </div>
              
              <!-- 默认内容渲染 -->
              <span v-else :style="getCellStyle(column, scope.row)">
                {{ formatCellValue(column, scope.row) }}
              </span>
            </slot>
          </template>
        </el-table-column>
      </template>
      
      <!-- 操作列 -->
      <el-table-column
        v-if="operations && operations.length > 0"
        :label="operationLabel"
        :width="operationWidth"
        :fixed="operationFixed"
        align="center"
      >
        <template #default="scope">
          <slot name="operation" :row="scope.row" :index="scope.$index">
            <div class="operation-buttons">
              <component
                v-for="(operation, opIndex) in resolveOperations(operations, scope.row)"
                :key="opIndex"
                :is="operation.component || 'el-button'"
                v-bind="operation.props || {}"
                :disabled="operation.disabled"
                :style="operation.style"
                :class="operation.class"
                v-show="isButtonVisible(operation, scope.row)"
                @click.stop="handleOperationClick(operation, scope.row, scope.$index, $event)"
              >
                <template v-if="operation.icon">
                  <component :is="operation.icon" v-if="typeof operation.icon === 'object'" />
                  <i v-else :class="operation.icon"></i>
                </template>
                {{ operation.label }}
              </component>
            </div>
          </slot>
        </template>
      </el-table-column>
      
      <!-- 空状态插槽 -->
      <template #empty>
        <slot name="empty">
          <el-empty :image-size="100" :description="emptyText" />
        </slot>
      </template>
      
      <!-- 追加内容插槽 -->
      <template #append>
        <slot name="append"></slot>
      </template>
    </el-table>
    
    <!-- 分页 -->
    <div v-if="showPagination" class="pagination-container">
      <slot name="pagination">
        <el-pagination
          v-model:current-page="currentPage"
          v-model:page-size="pageSize"
          :page-sizes="pageSizes"
          :layout="paginationLayout"
          :total="total"
          :small="smallPagination"
          :background="paginationBackground"
          :disabled="paginationDisabled"
          :hide-on-single-page="hideOnSinglePage"
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
          @prev-click="handlePrevPage"
          @next-click="handleNextPage"
        />
      </slot>
    </div>
    
    <slot name="afterTable"></slot>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  name: 'MTable',
  inheritAttrs: false
})
</script>

<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import type { Component } from 'vue'

// 定义表格列类型
interface TableColumn {
  prop: string;
  label: string;
  width?: string | number;
  minWidth?: string | number;
  fixed?: boolean | string;
  sortable?: boolean | string;
  showOverflowTooltip?: boolean;
  align?: 'left' | 'center' | 'right';
  formatter?: (row: any, column: TableColumn, cellValue: any, index: number) => any;
  renderHeader?: boolean;
  headerComponent?: Component | string;
  renderContent?: (row: any, column: TableColumn, index: number) => Component | string;
  component?: Component | string;
  componentProps?: Record<string, any> | ((row: any) => Record<string, any>);
  buttons?: Array<TableButton> | ((row: any) => Array<TableButton>);
  customClass?: string;
  customStyle?: Record<string, any> | ((row: any) => Record<string, any>);
  formatter?: (row: any, column: TableColumn, cellValue: any, index: number) => any;
  valueMap?: Record<string, any>;
  [key: string]: any;
}

// 定义表格按钮类型
interface TableButton {
  label?: string;
  action?: string;
  component?: Component | string;
  icon?: string | Component;
  props?: Record<string, any>;
  style?: Record<string, any>;
  class?: string | string[] | Record<string, boolean>;
  disabled?: boolean | ((row: any) => boolean);
  visible?: boolean | ((row: any) => boolean);
  onClick?: (row: any, index: number, event: Event) => void;
  [key: string]: any;
}

// 定义表格操作按钮类型
interface TableOperation extends TableButton {}

// 定义分页参数类型
interface Pagination {
  current: number;
  size: number;
  total: number;
}

// 定义组件Props
const props = withDefaults(defineProps<{
  // 表格数据
  tableData: any[];
  // 表格列配置
  columns: TableColumn[];
  // 表格行唯一标识
  rowKey?: string;
  // 表格高度
  tableHeight?: string | number;
  // 是否显示序号列
  showIndex?: boolean;
  // 序号列标题
  indexLabel?: string;
  // 序号列宽度
  indexWidth?: string | number;
  // 是否显示选择列
  showSelection?: boolean;
  // 选择列宽度
  selectionWidth?: string | number;
  // 可选择行的条件函数
  selectable?: (row: any, index: number) => boolean;
  // 是否可展开
  expandable?: boolean;
  // 展开列宽度
  expandWidth?: string | number;
  // 操作列配置
  operations?: TableOperation[];
  // 操作列标题
  operationLabel?: string;
  // 操作列宽度
  operationWidth?: string | number;
  // 操作列是否固定
  operationFixed?: boolean | string;
  // 表头单元格样式
  headerCellStyle?: Record<string, any>;
  // 行类名
  rowClassName?: string | ((params: { row: any, rowIndex: number }) => string);
  // 单元格类名
  cellClassName?: string | ((params: { row: any, column: any, rowIndex: number, columnIndex: number }) => string);
  // 空数据文本
  emptyText?: string;
  // 初始选中行
  selectedRows?: any[];
  // 是否显示分页
  showPagination?: boolean;
  // 当前页码
  currentPage?: number;
  // 每页数量
  pageSize?: number;
  // 可选每页数量选项
  pageSizes?: number[];
  // 分页布局
  paginationLayout?: string;
  // 总数据量
  total?: number;
  // 是否小型分页
  smallPagination?: boolean;
  // 分页带背景
  paginationBackground?: boolean;
  // 分页是否禁用
  paginationDisabled?: boolean;
  // 单页是否隐藏分页
  hideOnSinglePage?: boolean;
  // 是否使用内部分页逻辑
  useInternalPagination?: boolean;
}>(), {
  rowKey: 'id',
  tableHeight: 'auto',
  showIndex: false,
  indexLabel: '序号',
  indexWidth: 60,
  showSelection: false,
  selectionWidth: 50,
  selectable: () => true,
  expandable: false,
  expandWidth: 50,
  operations: () => [],
  operationLabel: '操作',
  operationWidth: 'auto',
  operationFixed: 'right',
  headerCellStyle: () => ({ background: '#eef1f6', color: '#606266' }),
  emptyText: '暂无数据',
  selectedRows: () => [],
  showPagination: false,
  currentPage: 1,
  pageSize: 10,
  pageSizes: [10, 20, 50, 100],
  paginationLayout: 'total, sizes, prev, pager, next, jumper',
  total: 0,
  smallPagination: false,
  paginationBackground: false,
  paginationDisabled: false,
  hideOnSinglePage: false,
  useInternalPagination: false
})

// 定义事件
const emit = defineEmits<{
  // 选择变更事件
  (e: 'selection-change', selection: any[]): void;
  // 行点击事件
  (e: 'row-click', row: any, column: any, event: Event): void;
  // 排序变更事件
  (e: 'sort-change', params: { column: any, prop: string, order: string | null }): void;
  // 按钮点击事件
  (e: 'button-click', params: { button: TableButton, row: any, index: number, event: Event }): void;
  // 操作点击事件
  (e: 'operation-click', params: { operation: TableOperation, row: any, index: number, event: Event }): void;
  // 组件点击事件
  (e: 'component-click', params: { column: TableColumn, row: any, index: number, event: Event }): void;
  // 页码变更事件
  (e: 'current-change', current: number): void;
  // 页大小变更事件
  (e: 'size-change', size: number): void;
  // 分页数据变更
  (e: 'pagination-change', pagination: Pagination): void;
  // 上一页事件
  (e: 'prev-page', current: number): void;
  // 下一页事件
  (e: 'next-page', current: number): void;
  // 更新分页值
  (e: 'update:current-page', current: number): void;
  (e: 'update:page-size', size: number): void;
  (e: 'update:total', total: number): void;
  (e: 'update:selected-rows', rows: any[]): void;
}>()

// 当前选中的行数据
const selectedData = ref<any[]>([])

// 初始选中的数据
watch(() => props.selectedRows, (val) => {
  if (val && val.length) {
    selectedData.value = val
  } else {
    selectedData.value = []
  }
}, { immediate: true, deep: true })

// 内部分页参数
const currentPage = ref(props.currentPage)
const pageSize = ref(props.pageSize)

// 监听分页参数变化
watch(() => props.currentPage, (val) => {
  currentPage.value = val
})

watch(() => props.pageSize, (val) => {
  pageSize.value = val
})

// 监听total变化
watch(() => props.total, (val) => {
  // 处理total变化后，当前页可能超出最大页数的情况
  if (val > 0) {
    const maxPage = Math.ceil(val / pageSize.value)
    if (currentPage.value > maxPage) {
      currentPage.value = maxPage
      emit('update:current-page', maxPage)
    }
  }
})

// 处理选择变更
const handleSelectionChange = (selection: any[]) => {
  selectedData.value = selection
  emit('selection-change', selection)
  emit('update:selected-rows', selection)
}

// 处理行点击
const handleRowClick = (row: any, column: any, event: Event) => {
  emit('row-click', row, column, event)
}

// 处理排序变更
const handleSortChange = (params: { column: any, prop: string, order: string | null }) => {
  emit('sort-change', params)
}

// 处理组件点击
const handleComponentClick = (column: TableColumn, row: any, index: number, event: Event) => {
  emit('component-click', { column, row, index, event })
}

// 处理按钮点击
const handleButtonClick = (button: TableButton, row: any, index: number, event: Event) => {
  // 如果按钮有自定义点击处理函数，则调用
  if (button.onClick && typeof button.onClick === 'function') {
    button.onClick(row, index, event)
  }
  
  // 触发通用按钮点击事件
  emit('button-click', { button, row, index, event })
  
  // 根据按钮类型触发特定操作事件
  if (button.action) {
    switch (button.action) {
      case 'edit':
      case 'update':
        emit('operation-click', { operation: { ...button, type: 'edit' }, row, index, event })
        break
      case 'delete':
      case 'remove':
        emit('operation-click', { operation: { ...button, type: 'delete' }, row, index, event })
        break
      case 'view':
      case 'detail':
        emit('operation-click', { operation: { ...button, type: 'view' }, row, index, event })
        break
      default:
        emit('operation-click', { operation: { ...button, type: button.action }, row, index, event })
    }
  }
}

// 处理操作列按钮点击
const handleOperationClick = (operation: TableOperation, row: any, index: number, event: Event) => {
  handleButtonClick(operation, row, index, event)
}

// 判断按钮是否显示
const isButtonVisible = (button: TableButton, row: any) => {
  if (button.visible === undefined) return true
  
  if (typeof button.visible === 'function') {
    return button.visible(row)
  }
  
  return button.visible
}

// 获取组件属性
const getComponentProps = (column: TableColumn, row: any) => {
  if (!column.componentProps) return {}
  
  if (typeof column.componentProps === 'function') {
    return column.componentProps(row)
  }
  
  return column.componentProps
}

// 格式化单元格值
const formatCellValue = (column: TableColumn, row: any) => {
  if (!row || !column.prop) return ''
  
  const value = row[column.prop]
  
  // 如果有格式化函数，使用格式化函数
  if (column.formatter && typeof column.formatter === 'function') {
    return column.formatter(row, column, value, -1)
  }
  
  // 如果有映射表，使用映射表
  if (column.valueMap && value !== undefined && value !== null) {
    return column.valueMap[value] ?? value
  }
  
  return value
}

// 获取单元格样式
const getCellStyle = (column: TableColumn, row: any) => {
  if (!column.customStyle) return {}
  
  if (typeof column.customStyle === 'function') {
    return column.customStyle(row)
  }
  
  return column.customStyle
}

// 处理按钮数组或函数
const resolveButtons = (buttons: Array<TableButton> | ((row: any) => Array<TableButton>), row: any) => {
  if (typeof buttons === 'function') {
    return buttons(row) || []
  }
  
  return buttons || []
}

// 处理操作列按钮
const resolveOperations = (operations: TableOperation[], row: any) => {
  return operations.filter(op => {
    if (op.visible === undefined) return true
    
    if (typeof op.visible === 'function') {
      return op.visible(row)
    }
    
    return op.visible
  })
}

// 处理分页大小变更
const handleSizeChange = (size: number) => {
  pageSize.value = size
  emit('size-change', size)
  emit('update:page-size', size)
  
  // 触发综合分页变更事件
  emit('pagination-change', {
    current: currentPage.value,
    size,
    total: props.total
  })
}

// 处理页码变更
const handleCurrentChange = (current: number) => {
  currentPage.value = current
  emit('current-change', current)
  emit('update:current-page', current)
  
  // 触发综合分页变更事件
  emit('pagination-change', {
    current,
    size: pageSize.value,
    total: props.total
  })
}

// 处理上一页
const handlePrevPage = (current: number) => {
  emit('prev-page', current)
}

// 处理下一页
const handleNextPage = (current: number) => {
  emit('next-page', current)
}

// 暴露给父组件的方法
defineExpose({
  // 获取当前选中数据
  getSelectedData: () => selectedData.value,
  // 清空选中
  clearSelection: () => {
    selectedData.value = []
  },
  // 获取当前页数据（适用于useInternalPagination为true时）
  getCurrentPageData: () => {
    if (!props.useInternalPagination) return props.tableData
    
    const start = (currentPage.value - 1) * pageSize.value
    const end = start + pageSize.value
    return props.tableData.slice(start, end)
  },
  // 设置当前页
  setCurrentPage: (page: number) => {
    currentPage.value = page
    emit('update:current-page', page)
  },
  // 设置页大小
  setPageSize: (size: number) => {
    pageSize.value = size
    emit('update:page-size', size)
  }
})
</script>

<style lang="scss" scoped>
.m-table-container {
  width: 100%;
  
  :deep(.el-table) {
    margin-bottom: 20px;
    width: 100%;
    
    .el-table__header-wrapper th {
      word-break: break-word;
      background-color: #f5f7fa;
      color: #606266;
      font-weight: 500;
      padding: 12px 0;
    }
    
    .el-table__row {
      &:hover {
        td {
          background-color: #f5f7fa;
        }
      }
    }
    
    .el-table__empty-block {
      min-height: 160px;
      display: flex;
      justify-content: center;
      align-items: center;
    }
  }
  
  .button-group,
  .operation-buttons {
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    gap: 5px;
    
    .el-button {
      padding: 5px 15px;
      min-height: 28px;
      line-height: 1;
      margin: 0;
    }
    
    .el-button + .el-button {
      margin-left: 5px;
    }
  }
  
  .pagination-container {
    display: flex;
    justify-content: flex-end;
    margin-top: 15px;
  }
}
</style>
 